package org.jsola.hr.service.impl;

import org.jsola.core.Page;
import org.jsola.hr.common.ExampleKit;
import org.jsola.hr.constant.HrConstants;
import org.jsola.hr.constant.PunchStatus;
import org.jsola.hr.constant.PunchType;
import org.jsola.hr.dao.IAttendPunchDailyReportDAO;
import org.jsola.hr.dao.IAttendPunchRecordDAO;
import org.jsola.hr.dto.AttendPunchDailyReportAddDTO;
import org.jsola.hr.dto.AttendPunchDailyReportUpdateDTO;
import org.jsola.hr.entity.AttendPeriodStatDO;
import org.jsola.hr.entity.AttendPlanDO;
import org.jsola.hr.entity.AttendPunchDailyReportDO;
import org.jsola.hr.entity.AttendPunchRecordDO;
import org.jsola.hr.query.*;
import org.jsola.hr.service.IAttendPeriodStatService;
import org.jsola.hr.service.IAttendPlanService;
import org.jsola.hr.service.IAttendPunchDailyReportService;
import org.jsola.hr.service.IAttendPunchRecordService;
import org.jsola.hr.vo.*;
import org.jsola.user.core.TokenUser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import tk.mybatis.mapper.entity.Example;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author zhr
 */
@Service("hrAttendPunchDailyReportServiceImpl")
public class AttendPunchDailyReportServiceImpl implements IAttendPunchDailyReportService {

    @Autowired
    private IAttendPunchDailyReportDAO attendPunchDailyReportDAO;
    @Autowired
    private IAttendPunchRecordService attendPunchRecordService;
    @Autowired
    private IAttendPeriodStatService attendPeriodStatService;
    @Autowired
    private IAttendPlanService attendPlanService;
    @Autowired
    private IAttendPunchRecordDAO attendPunchRecordDAO;

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public AttendPunchDailyReportVO save(AttendPunchDailyReportAddDTO attendPunchDailyReportAddDTO, TokenUser tokenUser) {
        // 转DO
        AttendPunchDailyReportDO attendPunchDailyReportDO = attendPunchDailyReportAddDTO.to(AttendPunchDailyReportDO.class);
        // 保存
        attendPunchDailyReportDO = save(attendPunchDailyReportDO, tokenUser.getSiteId(), tokenUser.getUserId());
        return attendPunchDailyReportDO.to(AttendPunchDailyReportVO.class);
    }

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public int update(AttendPunchDailyReportUpdateDTO attendPunchDailyReportUpdateDTO, TokenUser tokenUser) {
        //转DO
        AttendPunchDailyReportDO attendPunchDailyReportDO = attendPunchDailyReportUpdateDTO.to(AttendPunchDailyReportDO.class);
        //根据主键更新，只更新非null值
        return updateByIdSelective(attendPunchDailyReportDO, tokenUser.getSiteId(), tokenUser.getUserId());
    }

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public int deleteByIds(TokenUser tokenUser, String... attendPunchDailyReportIds) {
        return logicalDeleteByIds(tokenUser.getSiteId(), tokenUser.getUserId(), (Object[]) attendPunchDailyReportIds);
    }


    @Override
    public AttendPunchDailyReportVO selectById(String attendPunchDailyReportId, String siteId) {
        AttendPunchDailyReportDO attendPunchDailyReportDO = selectDOById(attendPunchDailyReportId, siteId);
        if (attendPunchDailyReportDO == null) {
            return null;
        }
        return attendPunchDailyReportDO.to(AttendPunchDailyReportVO.class);
    }

    @Override
    public List<AttendPunchDailyReportListVO> select(AttendPunchDailyReportQuery attendPunchDailyReportQuery, String siteId) {
        List<AttendPunchDailyReportDO> attendPunchDailyReportDOList = selectDO(attendPunchDailyReportQuery, siteId);
        if(CollectionUtils.isEmpty(attendPunchDailyReportDOList)) {
            return attendPunchDailyReportDOList == null ? null : new ArrayList<>();
        }
        return attendPunchDailyReportDOList.stream()
                .map(attendPunchDailyReportDO -> attendPunchDailyReportDO.to(AttendPunchDailyReportListVO.class))
                .collect(Collectors.toList());
    }

    @Override
    public int selectCount(AttendPunchDailyReportQuery attendPunchDailyReportQuery, String siteId) {
        Example example = buildExample(attendPunchDailyReportQuery,siteId);
        return attendPunchDailyReportDAO.selectCountByExample(example);
    }

    @Override
    public Page<AttendPunchDailyReportListVO> selectPage(AttendRecordStatQuery attendRecordStatQuery, String siteId) {

        attendRecordStatQuery.addOrder("gmtCreate", true);

        Example example = buildExampleReport(attendRecordStatQuery,siteId);
        Page<AttendPunchDailyReportDO> page = attendPunchDailyReportDAO.selectPageByExample(example,
                attendRecordStatQuery.getPageNo(),
                attendRecordStatQuery.getPageSize());

        Page<AttendPunchDailyReportListVO> pageRes = page.to(AttendPunchDailyReportListVO.class);

        if (pageRes.getEntities() != null && pageRes.getEntities().size() > 0) {

            List<AttendPunchDailyReportListVO> dataList = pageRes.getEntities();
            for (int i = 0; i < dataList.size(); i++) {

                AttendPunchDailyReportListVO data = dataList.get(i);

                // 查询考勤规则
                AttendPlanDO attendPlanDO = attendPlanService.selectDOById(data.getAttendPlanId(), siteId);
                if (attendPlanDO != null) {
                    data.setAttendPlanName(attendPlanDO.getName());
                }
                else {
                    data.setAttendPlanName("");
                }

                // 工作时长
                if (data.getWorkTimeMinute() != null && data.getWorkTimeMinute() != 0) {

                    int hours = (int) Math.floor(data.getWorkTimeMinute() / 60);
                    int minute = data.getWorkTimeMinute() % 60;
                    String  workTimeMinuteStr = hours + "小时" + minute + "分钟";
                    data.setWorkTimeMinuteStr(workTimeMinuteStr);
                }
                else {
                    data.setWorkTimeMinuteStr("0小时");
                }
                // 校准状态-展示
                if (data.getAttendStatus() != null) {
                    String attendStatusStr = PunchType.find(data.getAttendStatus()).getDesc();
                    data.setAttendStatusStr(attendStatusStr);
                }

                // 加班时长-展示
                if (data.getOvertimeHours() != null) {

                    int overtimeHoursInt = data.getOvertimeHours().intValue();
                    int hours = (int) Math.floor(overtimeHoursInt / 60);
                    int minute = overtimeHoursInt % 60;
                    String  overtimeHoursStr = hours + "小时" + minute + "分钟";
                    data.setOvertimeHoursStr(overtimeHoursStr);
                }
                else {
                    data.setOvertimeHoursStr("0小时");
                }
            }
        }


        return pageRes;
    }

    @Override
    public AttendPunchDailyReportDO selectDOById(String attendPunchDailyReportId, String siteId) {
        return listById(attendPunchDailyReportId, siteId);
    }

    @Override
    public List<AttendPunchDailyReportDO> selectDO(AttendPunchDailyReportQuery attendPunchDailyReportQuery, String siteId) {
        Example example = buildExample(attendPunchDailyReportQuery,siteId);
        return attendPunchDailyReportDAO.selectByExample(example);
    }

    @Override
    public List<AttendDailyPeriodVO> selectAttendStatus(AttendStatusQuery attendStatusQuery, String siteId) {

        List<AttendDailyPeriodVO> periodList = new ArrayList<>();

        // 根据ID查询
        AttendPunchDailyReportDO attendPunchDailyReportDO = this.selectDOById(attendStatusQuery.getDailyReportId(), siteId);
        if (attendPunchDailyReportDO == null) {
            return periodList;
        }

        // 查询考勤打卡记录
        AttendPunchRecordQuery attendPunchRecordQuery = new AttendPunchRecordQuery();
        attendPunchRecordQuery.setAttendPlanId(attendPunchDailyReportDO.getAttendPlanId());
        attendPunchRecordQuery.setEmpInfoId(attendPunchDailyReportDO.getEmpInfoId());
        attendPunchRecordQuery.setYear(attendPunchDailyReportDO.getYearly());
        attendPunchRecordQuery.setMonth(attendPunchDailyReportDO.getMonthly());
        attendPunchRecordQuery.setDay(attendPunchDailyReportDO.getDaily());
        List<AttendPunchRecordDO> attendPunchRecordList = attendPunchRecordService.selectDO(attendPunchRecordQuery, siteId);

        List<String> attendRecordIds = new ArrayList<>();
        for (AttendPunchRecordDO record : attendPunchRecordList) {
            attendRecordIds.add(record.getId());
        }

        // 查询考勤打卡时间段
        AttendPeriodStatQuery attendPeriodStatQuery = new AttendPeriodStatQuery();
        attendPeriodStatQuery.setAttendRecordIds(attendRecordIds);
        List<AttendPeriodStatDO> attendPeriodStatList = attendPeriodStatService.selectDO(attendPeriodStatQuery ,siteId);

        Map<String, List<String>> periodMap = new HashMap<String, List<String>>();

        // 将时间段放入MAP中
        for (AttendPeriodStatDO attendPeriodStat : attendPeriodStatList) {

            List<String> recordIds = periodMap.get(attendPeriodStat.getPeriod());
            if (recordIds == null) {
                recordIds = new ArrayList<>();
                recordIds.add(attendPeriodStat.getAttendRecordId());
                periodMap.put(attendPeriodStat.getPeriod(), recordIds);
            }
            else {
                recordIds.add(attendPeriodStat.getAttendRecordId());
                periodMap.put(attendPeriodStat.getPeriod(), recordIds);
            }
        }

        // 每日多条打卡记录
        Map<String, List<AttendDailyStatusVO>> dailyMap = new HashMap<String, List<AttendDailyStatusVO>>();

        // 遍历map ，获取时间段
        for(Map.Entry<String, List<String>> entry : periodMap.entrySet()) {

            // 时段
            String period = entry.getKey();
            // 考勤记录ids
            List<String> recordIds = entry.getValue();

            for (String recordId : recordIds) {
                // 根据ID查询考勤记录
                AttendPunchRecordDO attendPunchRecordDO = attendPunchRecordService.selectDOById(recordId, siteId);
                if (attendPunchRecordDO != null) {
                    String ymd = attendPunchRecordDO.getYear() + "-" + attendPunchRecordDO.getMonth() + "-" + attendPunchRecordDO.getDay();

                    List<AttendDailyStatusVO> dailyList = dailyMap.get(ymd);
                    if (dailyList == null) {
                        dailyList = new ArrayList<>();
                    }

                    AttendDailyStatusVO attendDailyStatusVO = new AttendDailyStatusVO();
                    // 上班或下班状态-展示
                    attendDailyStatusVO.setWorkStatusStr(PunchStatus.find(attendPunchRecordDO.getPunchStatus()).getDesc());
                    // 上班或下班状态
                    attendDailyStatusVO.setWorkStatus(attendPunchRecordDO.getPunchStatus());
                    // 上班或下班ID
                    attendDailyStatusVO.setWorkId(attendPunchRecordDO.getId());
                    // 时间点
//                    attendDailyStatusVO.setTimePoint(attendPunchRecordDO.getStandardTime());

                    dailyList.add(attendDailyStatusVO);
                    dailyMap.put(ymd, dailyList);
                }
            }

            // 每日考勤日期
            List<AttendDailyDateVO> dailyDateList = new ArrayList<>();

            // 遍历dailyMap
            for(Map.Entry<String, List<AttendDailyStatusVO>> daily : dailyMap.entrySet()) {

                String ymd = daily.getKey();
                List<AttendDailyStatusVO> dataList = daily.getValue();

                AttendDailyDateVO attendDailyDateVO = new AttendDailyDateVO();
                attendDailyDateVO.setYearly(ymd.split("-")[0]);
                attendDailyDateVO.setMonthly(ymd.split("-")[1]);
                attendDailyDateVO.setDaily(ymd.split("-")[2]);
                attendDailyDateVO.setDailyStatusList(dataList);

                dailyDateList.add(attendDailyDateVO);
            }


            AttendDailyPeriodVO attendDailyPeriodVO = new AttendDailyPeriodVO();
            attendDailyPeriodVO.setPeriod(period);
            attendDailyPeriodVO.setDailyDateList(dailyDateList);

            periodList.add(attendDailyPeriodVO);
        }

        return periodList;
    }

    @Override
    public List<AttendPunchRecordSimpleVO> selectSimpleRecordList(AttendPunchRecordSimpleQuery attendPunchRecordSimpleQuery, String siteId) {

        List<AttendPunchRecordSimpleVO> simpleList = new ArrayList<>();

        Example example = new Example(AttendPunchRecordDO.class);
        example.and()
                .andEqualTo("valid", true)
                .andEqualTo("siteId", siteId);

        example.and().andEqualTo("attendPlanId", attendPunchRecordSimpleQuery.getAttendPlanId());
        example.and().andEqualTo("empInfoId", attendPunchRecordSimpleQuery.getEmpInfoId());
        example.and().andEqualTo("yearly", attendPunchRecordSimpleQuery.getYmd().split("-")[0]);
        example.and().andEqualTo("monthly", attendPunchRecordSimpleQuery.getYmd().split("-")[1]);
        example.and().andEqualTo("daily", attendPunchRecordSimpleQuery.getYmd().split("-")[2]);

        example.setOrderByClause("gmt_create desc");

        List<AttendPunchRecordDO> dataList = attendPunchRecordDAO.selectByExample(example);
        if (dataList != null && dataList.size() > 0) {

            dataList.forEach(data -> {
                simpleList.add(data.to(AttendPunchRecordSimpleVO.class));
            });
        }

        return simpleList;
    }

    /**
     * 根据查询参数，构建example
     * @param attendRecordStatQuery 查询参数
     * @param siteId 所属站点id
     * @return example
     */
    private Example buildExampleReport(AttendRecordStatQuery attendRecordStatQuery, String siteId) {
        Example example = new Example(AttendPunchDailyReportDO.class);
        example.and()
                .andEqualTo("valid", true)
                .andEqualTo("siteId", siteId);

        if (attendRecordStatQuery.getCompanyId() != null) {
            example.and().andEqualTo("companyId", attendRecordStatQuery.getCompanyId());
        }
        if (attendRecordStatQuery.getEmpInfoName() != null) {
            example.and().andLike("empInfoName", "%" + attendRecordStatQuery.getEmpInfoName() +"%");
        }
        if (attendRecordStatQuery.getDeptId() != null) {
            example.and().andEqualTo("deptId", attendRecordStatQuery.getDeptId());
        }
        if (attendRecordStatQuery.getYmd() != null) {
            example.and().andEqualTo("yearly", attendRecordStatQuery.getYmd().split("-")[0]);
            example.and().andEqualTo("monthly", attendRecordStatQuery.getYmd().split("-")[1]);
            example.and().andEqualTo("daily", attendRecordStatQuery.getYmd().split("-")[2]);
        }
        if (attendRecordStatQuery.getPunchStatus() != null) {
            example.and().andEqualTo("hisAttendStatus", attendRecordStatQuery.getPunchStatus());
        }

        // 排序
        ExampleKit.setExampleOrder(example,attendRecordStatQuery.getOrders());
        return example;
    }


    /**
     * 根据查询参数，构建example

     * @param attendPunchDailyReportQuery 查询参数
     * @param siteId 所属站点id
     * @return example
     */
    private Example buildExample(AttendPunchDailyReportQuery attendPunchDailyReportQuery, String siteId) {
        Example example = new Example(AttendPunchDailyReportDO.class);
        example.and()
                .andEqualTo("valid", true)
                .andEqualTo("siteId", siteId);
        if (attendPunchDailyReportQuery.getDailySummaryId() != null) {
            example.and().andEqualTo("dailySummaryId", attendPunchDailyReportQuery.getDailySummaryId());
        }
        if (attendPunchDailyReportQuery.getCompanyId() != null) {
            example.and().andEqualTo("companyId", attendPunchDailyReportQuery.getCompanyId());
        }
        if (attendPunchDailyReportQuery.getCompanyName() != null) {
            example.and().andEqualTo("companyName", attendPunchDailyReportQuery.getCompanyName());
        }
        if (attendPunchDailyReportQuery.getDeptId() != null) {
            example.and().andEqualTo("deptId", attendPunchDailyReportQuery.getDeptId());
        }
        if (attendPunchDailyReportQuery.getDeptName() != null) {
            example.and().andEqualTo("deptName", attendPunchDailyReportQuery.getDeptName());
        }
        if (attendPunchDailyReportQuery.getAttendPlanId() != null) {
            example.and().andEqualTo("attendPlanId", attendPunchDailyReportQuery.getAttendPlanId());
        }
        if (attendPunchDailyReportQuery.getEmpInfoId() != null) {
            example.and().andEqualTo("empInfoId", attendPunchDailyReportQuery.getEmpInfoId());
        }
        if (attendPunchDailyReportQuery.getEmpInfoName() != null) {
            example.and().andEqualTo("empInfoName", attendPunchDailyReportQuery.getEmpInfoName());
        }
        if (attendPunchDailyReportQuery.getYearly() != null) {
            example.and().andEqualTo("yearly", attendPunchDailyReportQuery.getYearly());
        }
        if (attendPunchDailyReportQuery.getMonthly() != null) {
            example.and().andEqualTo("monthly", attendPunchDailyReportQuery.getMonthly());
        }
        if (attendPunchDailyReportQuery.getDaily() != null) {
            example.and().andEqualTo("daily", attendPunchDailyReportQuery.getDaily());
        }
        if (attendPunchDailyReportQuery.getSignInLocation() != null) {
            example.and().andEqualTo("signInLocation", attendPunchDailyReportQuery.getSignInLocation());
        }
        if (attendPunchDailyReportQuery.getSignOutLocation() != null) {
            example.and().andEqualTo("signOutLocation", attendPunchDailyReportQuery.getSignOutLocation());
        }
        if (attendPunchDailyReportQuery.getIsGoOut() != null) {
            example.and().andEqualTo("isGoOut", attendPunchDailyReportQuery.getIsGoOut());
        }
        if (attendPunchDailyReportQuery.getGoOutLocation() != null) {
            example.and().andEqualTo("goOutLocation", attendPunchDailyReportQuery.getGoOutLocation());
        }
        if (attendPunchDailyReportQuery.getGoOutHoursStart() != null &&
                attendPunchDailyReportQuery.getGoOutHoursEnd() != null) {
            example.and().andBetween("goOutHours", attendPunchDailyReportQuery.getGoOutHoursStart(),
                    attendPunchDailyReportQuery.getGoOutHoursEnd());
        }
        if (attendPunchDailyReportQuery.getIsUsed() != null) {
            example.and().andEqualTo("isUsed", attendPunchDailyReportQuery.getIsUsed());
        }
        if (attendPunchDailyReportQuery.getAttendStatus() != null) {
            example.and().andEqualTo("attendStatus", attendPunchDailyReportQuery.getAttendStatus());
        }
        if (attendPunchDailyReportQuery.getOvertimeHoursStart() != null &&
                attendPunchDailyReportQuery.getOvertimeHoursEnd() != null) {
            example.and().andBetween("overtimeHours", attendPunchDailyReportQuery.getOvertimeHoursStart(),
                    attendPunchDailyReportQuery.getOvertimeHoursEnd());
        }
        if (attendPunchDailyReportQuery.getEarliestTime() != null) {
            example.and().andEqualTo("earliestTime", attendPunchDailyReportQuery.getEarliestTime());
        }
        if (attendPunchDailyReportQuery.getLatestTime() != null) {
            example.and().andEqualTo("latestTime", attendPunchDailyReportQuery.getLatestTime());
        }
        if (attendPunchDailyReportQuery.getPunchCounts() != null) {
            example.and().andEqualTo("punchCounts", attendPunchDailyReportQuery.getPunchCounts());
        }
        if (attendPunchDailyReportQuery.getWorkTimeMinute() != null) {
            example.and().andEqualTo("workTimeMinute", attendPunchDailyReportQuery.getWorkTimeMinute());
        }
        if (attendPunchDailyReportQuery.getHisAttendStatus() != null) {
            example.and().andEqualTo("hisAttendStatus", attendPunchDailyReportQuery.getHisAttendStatus());
        }
        if (attendPunchDailyReportQuery.getOvertimeStatus() != null) {
            example.and().andEqualTo("overtimeStatus", attendPunchDailyReportQuery.getOvertimeStatus());
        }
        if (attendPunchDailyReportQuery.getMinutes() != null) {
            example.and().andEqualTo("minutes", attendPunchDailyReportQuery.getMinutes());
        }
        // 排序
        ExampleKit.setExampleOrder(example,attendPunchDailyReportQuery.getOrders());
        return example;
    }
}




